/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package stub;
import business.Servidor;
import java.io.EOFException;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.util.logging.Level;
import java.util.logging.Logger;
import java.io.FileNotFoundException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.URL;


/**
 *
 * @author nacho
 */
public class Stub {
    static Tabla tabla = new Tabla();


    static public void main(String args[]) {
        URL puerto;
        Boolean seguir = true;
        Mensaje mensaje, respuesta;
        Servidor servidor = new Servidor();
        File archivo;
        String nombreArchivo;
        int fd = 0;
        Socket socketCliente;
        ServerSocket server;

        try {
            puerto = new URL("http", "localhost", Integer.valueOf(args[0]), "");
           // Network net = new Network(puerto);
            server = new ServerSocket(puerto.getPort());


            while (true) {
                try {
                    System.out.println("Esperando conexión cliente......");
                    //net.accept();
                    socketCliente = server.accept();
                    System.out.println("Se conecto un cliente en el puerto: " + socketCliente.getPort());

                    //while(seguir) {
                        //ensaje = net.receive();
                    mensaje = receive(socketCliente);

                        System.out.println("El cliente conectado en el puerto: " + socketCliente.getPort() + " hace operación: " + Protocolo.getInstance().desempaquetarCodOp(mensaje));
                        Thread.sleep(2000);

                        switch (Protocolo.getInstance().desempaquetarCodOp(mensaje)) {
                            case Protocolo.RFS_OPEN:
                                archivo = servidor.open(Protocolo.getInstance().desempaquetarNombreArchivo(mensaje), Protocolo.getInstance().desempaquetarWrite(mensaje));
                                if (archivo != null) {
                                    OpenFile fila = new OpenFile(archivo, archivo.getName());
                                    //System.out.println("Antes de tabla");
                                    fd = tabla.add(fila);
                                    //System.out.println("File descripto que devuelvo: " + fd);
                                    respuesta = Protocolo.getInstance().empaquetar(Protocolo.RFS_OPEN, "", Protocolo.OK, fd);
                                } else {
                                    if (Protocolo.getInstance().desempaquetarWrite(mensaje))
                                        respuesta = Protocolo.getInstance().empaquetar(Protocolo.RFS_OPEN, Protocolo.FILE_FOUND);
                                    else
                                        respuesta = Protocolo.getInstance().empaquetar(Protocolo.RFS_OPEN, Protocolo.FILE_NOT_FOUND);
                                }
                                ///net.send(respuesta);
                                send(socketCliente, respuesta);
                                break;

                            case Protocolo.RFS_READ:
                                nombreArchivo = Protocolo.getInstance().desempaquetarNombreArchivo(mensaje);
                                fd = Protocolo.getInstance().desempaquetarArchivo(mensaje);
                                //System.out.println("Fd que vino desde el cliente: " + fd);
                                //System.out.println("nombre de archivo: " + nombreArchivo);
                                if (checkFile(fd, nombreArchivo)) {
                                    OpenFile fila = tabla.get(fd);
                                    long aux = fila.getSeek();
                                    byte[] data = new byte[Protocolo.TAMANIO_BLOQUE];
                                    fila = servidor.read(fila, data);
                                    //System.out.println("texto: " + new String(data));
                                    aux = fila.getSeek() - aux;
                                    //System.out.println("Codigo: " + Protocolo.RFS_READ);
                                    respuesta = Protocolo.getInstance().empaquetar(Protocolo.RFS_READ, "", Protocolo.OK, data, aux);
                                } else {
                                    System.out.println("algun error sucedio");
                                    respuesta = Protocolo.getInstance().empaquetar(Protocolo.RFS_READ, Protocolo.FILE_NOT_FOUND);
                                }
                               // net.send(respuesta);
                                send(socketCliente, respuesta);
                                break;

                            case Protocolo.RFS_WRITE:
                                nombreArchivo = Protocolo.getInstance().desempaquetarNombreArchivo(mensaje);
                                fd = Protocolo.getInstance().desempaquetarArchivo(mensaje);
                                if (checkFile(fd, nombreArchivo)) {
                                    OpenFile fila = tabla.get(fd);
                                    byte[] data = Protocolo.getInstance().desempaquetarData(mensaje);
                                    long cargaUtil = Protocolo.getInstance().desempaquetarLongitudData(mensaje);
                                    servidor.write(fila, data, (int)cargaUtil);
                                    respuesta = Protocolo.getInstance().empaquetar(Protocolo.RFS_WRITE, Protocolo.OK);
                                } else {
                                    respuesta = Protocolo.getInstance().empaquetar(Protocolo.RFS_WRITE, Protocolo.FILE_NOT_FOUND);
                                }
                                //net.send(respuesta);
                                send(socketCliente, respuesta);
                                break;

                            case Protocolo.RFS_CLOSE:
                                nombreArchivo = Protocolo.getInstance().desempaquetarNombreArchivo(mensaje);
                                fd = Protocolo.getInstance().desempaquetarArchivo(mensaje);
                                if (checkFile(fd, nombreArchivo)) {
                                    tabla.remove(fd);
                                    respuesta = Protocolo.getInstance().empaquetar(Protocolo.RFS_CLOSE, Protocolo.OK);
                                } else {
                                    respuesta = Protocolo.getInstance().empaquetar(Protocolo.RFS_CLOSE, Protocolo.FILE_NOT_FOUND);
                                }
                                //net.send(respuesta);
                                send(socketCliente, respuesta);
                                seguir = false;
                                break;
                        }
                    //}
                    //net.close();
                        socketCliente.close();
                    //net = new Network(puerto);
                } catch (SocketException ex) {
                    System.out.println("El cliente se desconectó");
                    tabla.remove(fd);
                    System.out.println("El archivo ha sido liberado en la tabla");
                } catch (InterruptedException ex) {
                    Logger.getLogger(Stub.class.getName()).log(Level.SEVERE, null, ex);
                }
            } 
        } catch (MalformedURLException ex) {
            Logger.getLogger(Stub.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(Stub.class.getName()).log(Level.SEVERE, null, ex);
        }

    }


    private static boolean checkFile(int fd, String nombreArchivo) {
        OpenFile fila = tabla.get(fd);
        if (fila != null) {
            return (fila.getNombreArchivo().compareTo(nombreArchivo) == 0);
        } else {
            return false;
        }
    }

    private void tratarError(int error) throws ConnectionException, FileFoundException, IllegalAccessException, FileNotFoundException, OperationException {
        switch (error) {
            case Protocolo.ACCESS_DENIED:
                throw new IllegalAccessException("Acceso denegado");
            case Protocolo.CONECTION_FAILED:
                throw new ConnectionException("Falló la conexión");
            case Protocolo.FILE_FOUND:
                throw new FileFoundException();
            case Protocolo.FILE_NOT_FOUND:
                throw new FileNotFoundException("El archivo no existe");
            case Protocolo.OPERATION_ERROR:
                throw new OperationException("Error en la operación");
        }
    }

    public static void send(Socket cliente,Mensaje mensaje) {
        try {
            if (cliente.isConnected()) {
                // preparo todo para el envio del mensaje
                ObjectOutputStream flujo = new ObjectOutputStream(cliente.getOutputStream());

                flujo.flush();
                flujo.writeObject(mensaje);
                flujo.flush();

            }
        } catch (IOException ex) {
            System.err.println("#####################\n");
            System.err.println(ex.getMessage());
            ex.printStackTrace();
            System.err.println("#####################\n");
        }
    }

    private static Mensaje receive(Socket cliente) throws SocketException, IOException {
        Mensaje mensaje = new Mensaje();
        if (cliente.isConnected()) {
            try {
                // preparo todo para la recepcion del mensaje
                ObjectInputStream flujo = new ObjectInputStream(cliente.getInputStream());

                // recibo el mensaje
                mensaje = (Mensaje) flujo.readObject();

                // entrego el mensaje
                return mensaje;

            }
            catch (EOFException ex) {
                return null;
            }

            catch (ClassNotFoundException ex) {
                System.err.println("#####################\n");
                System.err.println(ex.getMessage());
                ex.printStackTrace();
                System.err.println("#####################\n");
            }
        }
        return null;

}
}
    
